-- /run for i=1,40 do local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId=UnitBuff("player",i); if name then print(name.."("..expirationTime..")".." = "..spellId) end end
-- /run for i=1,40 do local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId=UnitDebuff("target",i); if name then print(name.."="..spellId) end end

-- /run if GetSpellInfo(95799) then print("true") else print("false") end

-- get the addon namespace
local addon, ns = ...

-- get the config values
local cfg = ns.cfg
  
-- holder for some lib functions
local lib = _G["HEDD_lib"] or CreateFrame("Frame","HEDD_lib")
_G["HEDD_cfg"] = ns.cfg

local _,tl,tl_rune_any
local pcd,pstart,pduration,pruneReady,pruneType,pisUsable,pnotEnoughMana
local s, d, en, f
local pduration,pexpire,pstacks,ppresent
local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId
local stacks
local i,exist,buff
local pcombo,ppower,pground,range
local tl_rune_r,tl_rune_g,tl_rune_b,n_rune_r,n_rune_g,n_rune_b,RuneReady
local ExcludeRunes = {}
local start, finish, c_rune, tl_rune, ReadyRuneFound
local allrunes,numrunes
local update
local runeType
local pMain, pOff
local tl_bar
local tl_aura, s_aura, notfound_aura, i_aura, n_aura
local lastUpdateBar = 0
local tl_totem
local tl_spell
local tl_spell_energy
local cost_spell
local i_runes,j_runes
local i_spell, i_case, n_case
local shape=nil
local ctl
local icon
local spells,sname,ids,noupdate
local spells,ids,runemask
local auras,sname,id,atype,unit,caster
local index,id
local cspell
local cpower,tl_cspell,ct_spell


local queue = {}
queue.array = {}
queue.enqueue = function(element)
	if queue.rear() ~= element then
		table.insert(queue.array,element)
	end
end
queue.dequeue = function()
	local result = queue.array[1]
	if #(queue.array) > 0 then
		table.remove(queue.array,1)
	end
	return result
end
queue.front = function()
	return queue.array[1]
end
queue.rear = function()
	return queue.array[#(queue.array)]
end
queue.clear = function()
	queue.array = {}
end
cfg.queue = queue

lib.enqueueSpell = function(spellname)
	if queue.rear() == nil or (GetSpellInfo(spellname) ~= nil and queue.rear()["name"] ~= spellname) then
		queue.enqueue({["name"]=spellname,["time"]=GetTime()})
		cfg.Update = true
	end
end

lib.HideFrame = function(frame)
	if frame then frame:Hide() end
end

lib.inrange = function(spell)
	if cfg.spells[spell] and IsSpellInRange((cfg.spells[spell] and cfg.spells[spell].name or spell),"target")==0 then return nil end
	return true
end

lib.bdcolor = function(frame,color)
	if color then
		frame:SetBackdropColor(unpack(color))
		frame:SetBackdropBorderColor(unpack(color))
		frame:Show()
	else
		frame:Hide()
	end
end

lib.resetRaidMode = function()
for i = 1,8 do
	for j = 1,5 do
		local frm = _G["HEDD_RAID_FRM_"..((i-1)*5+j)] or CreateFrame("Button", "HEDD_RAID_FRM_"..((i-1)*5+j), UIParent, 'SecureActionButtonTemplate')
		local target = cfg.raidmode or 'party'
		
		target = target..((i-1)*5+j)
		frm:SetAttribute('type','target')
		frm:SetAttribute('unit',target)
	end
end
	local frm = _G["HEDD_RAID_FRM_"..(41)] or CreateFrame("Button", "HEDD_RAID_FRM_"..(41), UIParent, 'SecureActionButtonTemplate')
	
	frm:SetAttribute('type','target')
	frm:SetAttribute('unit','player')
end

lib.hideRuneFrame=function()
	RuneFrame:Hide()
	RuneFrame.Show = hedlib.dummy -- function() end
	RuneFrame.SetPoint = hedlib.dummy --function() end
	RuneFrame.ClearAllPoints = hedlib.dummy --function() end
	RuneFrame.SetAllPoints = hedlib.dummy --function() end
	RuneFrame:UnregisterEvent("RUNE_POWER_UPDATE");
	RuneFrame:UnregisterEvent("RUNE_TYPE_UPDATE");
	RuneFrame:UnregisterEvent("PLAYER_ENTERING_WORLD");
	RuneFrame:SetScript("OnEvent", nil);
	RuneFrame:SetParent(nil)
end

lib.clearCfg = function()
	cfg.plistdps = nil
	cfg.plistfulldps = nil
	cfg.plistlowdps = nil
	cfg.healingFlag = nil
	cfg.dpsmode = 'normal'
end

lib.createMacros = function()
	if GetMacroInfo('Low DPS') == nil then
		CreateMacro('Low DPS','Racial_Dwarf_FindTreasure','/run Hedd:SetDPSMode("low")')
	end
	if GetMacroInfo('Normal DPS') == nil then
		CreateMacro('Normal DPS','Spell_ChargeNegative','/run Hedd:SetDPSMode("normal")')
	end
	if GetMacroInfo('Full DPS') == nil then
		CreateMacro('Full DPS','Spell_ChargePositive','/run Hedd:SetDPSMode("full")')
	end
end

lib.getDPSModeText = function()
	if cfg.dpsmode == 'low' then
		return 'L'
	elseif cfg.dpsmode == 'normal' then
		return 'N'
	elseif cfg.dpsmode == 'full' then
		return 'F'
	end
	return 'N'
end

lib.changeDPSMode = function(mode)
	if mode == nil then 
		mode = cfg.dpsmode
	end
	if mode == 'low' and cfg.plistlowdps then
		cfg.dpsmode = mode
		if cfg.mode == 'dps' then
			cfg.plist = cfg.plistlowdps
		end
	elseif mode == 'normal' and cfg.plistdps then
		cfg.dpsmode = mode
		if cfg.mode == 'dps' then
			cfg.plist = cfg.plistdps
		end
	elseif mode == 'full' and cfg.plistfulldps then
		cfg.dpsmode = mode
		if cfg.mode == 'dps' then
			cfg.plist = cfg.plistfulldps
		end
	end
end

lib.setControlValue=function(frmnum,value1,value2,value3,value4,value5,value6)
	local frm = Heddframe.ctrlFrms[frmnum]
	if value4 == nil then
		value4 = value1
		value5 = value2
		value6 = value3
	end
	if(frm and frm.textureTR) then
		frm.textureTR:SetTexture(value1,value2,value3)
		frm.textureBL:SetTexture(value4,value5,value6)
	end
end
	
lib.setTalentControlFlag = function()
	--talent name
	if cfg.talentname ~= nil then
		array = {}
		for i = 1,4 do
			if i > string.len(cfg.talentname) then
				table.insert(array,0)
			else
				table.insert(array,string.byte(cfg.talentname,i))
			end
		end
		lib.setControlValue(3,array[1]/255,array[2]/255,0,array[3]/255,array[4]/255,0)
	else
		lib.setControlValue(3,0,0,0)
	end
end

lib.OnUpdateBar = function (self, elapsed) --Heddframe.bar=self
	elapsed = elapsed or 0
	lastUpdateBar = lastUpdateBar + elapsed
	if self.force or lastUpdateBar > cfg.freq then
		
		self.cd = self.cd - (cfg.now - self.start)
		self.cd = (self.cd>0) and self.cd or 0
		self.start=cfg.now

		if (self.cd>0) then
			self:SetWidth(self.cd*cfg.scale)
		else
			self:SetScript("OnUpdate", nil)
			self:SetWidth(-1)
		end

		lastUpdateBar = 0
		self.force=nil
	end	
end

lib.HideAllSpells = function ()
	for i_spell in pairs(cfg.spells) do
		lib.HideFrame(cfg.spells[i_spell].f)
	end
end

lib.UpdateBar = function (spell, cd)
	Heddframe.bar.start = cfg.now
	Heddframe.bar.cd = cd or 0
	if spell and cfg.spells[spell] then
		cfg.spells[spell].f:Show()
	end
	Heddframe.bar.force=true
	Heddframe.bar:SetScript("OnUpdate", lib.OnUpdateBar)
	lib.OnUpdateBar(Heddframe.bar)
end

local noprio=true
local prio_count=0
local counter = 0
lib.SetPriority = function()
	for i_spell in pairs(cfg.spells) do
		lib.HideFrame(cfg.spells[i_spell].f)
	end

	cfg.mintime = 0
	if cfg.casting then
		cfg.mintime=cfg.castEnd-cfg.now
		if cfg.mintime<0 then cfg.mintime=0 end
	end
	cfg.cmintime = cfg.maxmintime
	cfg.compensatePower = 0
	--print("reset compensate")
	noprio=true
	prio_count=0

	while noprio do
		prio_count=prio_count+1
		
		-- queue strategy
		local waitspell = nil
		--[[
		local debugq = ''
		for c,v in pairs(queue.array) do
			debugq = debugq..v['name']
		end
		print(#(queue.array)..'  '..debugq)
		]]
		if queue.front() ~= nil then
			local endflag = false
			while not endflag do
				endflag = true
				local front = queue.front()
				while front and ((cfg.lastspell ~= nil and cfg.lastspell == front['name']) or (UnitCastingInfo('player') and UnitCastingInfo('player') == front['name']) or GetTime() - front['time'] > 4) do
					queue.dequeue()
					front = queue.front()
				end
				if queue.front() ~= nil then
					waitspell = queue.front()['name']
					if not cfg.spells["QUEUE"] or (cfg.spells["QUEUE"] and cfg.spells["QUEUE"].name ~= waitspell) then
						lib.AddSpell("QUEUE",{waitspell})
						lib.UpdateSpellCD("QUEUE")
					end
					if lib.GetSpellCD('QUEUE') > 4 then
						waitspell = nil
						queue.dequeue()
						endflag = false
					end
				end
			end
		end
		if waitspell ~= nil then
			--print('NEW PRIORITY!')
			--print(cfg.spells["QUEUE"].cd - (cfg.now - cfg.spells["QUEUE"].start))
			--print(cfg.spells["QUEUE"].cd..' '..cfg.spells["QUEUE"].start)
			--print(cfg.mintime..' '..cfg.cmintime)
			if lib.SimpleCDCheck('QUEUE',0,true) then
				noprio = nil
			end
		else
			for i_case, n_case in pairs(cfg.plist) do
				if cfg.case[n_case] then
					if cfg.case[n_case]() then
						noprio=nil
						break
					end
				else
					if lib.SimpleCDCheck(n_case) then
						noprio=nil
						break
					end
				end
			end
		end
		--print(prio_count..'  '..cfg.numcase)
		if cfg.cmintime==cfg.maxmintime or prio_count>cfg.numcase then
			if (cfg.defaultdps and cfg.mode == "dps") then
				lib.HideAllSpells()
				lib.UpdateBar(cfg.defaultdps,lib.GetSpellCD(cfg.defaultdps))
				cfg.spells[cfg.defaultdps].f:Show()
				break
			else
				lib.HideAllSpells()
				cfg.emptySpell:Show()
			end
			lib.UpdateBar(nil)
			noprio=nil
			break
		end
		if noprio==nil then
			break
		end
		cfg.mintime=cfg.cmintime
	end
	Heddframe.bar.force=true
	--cfg.compensatePower = 0
end

lib.InitEmptySpellFrame = function()
	cfg.emptySpell = CreateFrame("Frame","HEDD_EmptySpell")
	cfg.emptySpell:SetAllPoints(Heddframe);
	cfg.emptySpell:SetWidth(cfg.isize)
	cfg.emptySpell:SetHeight(cfg.isize)
	cfg.emptySpell.texture = _G["HEDD_EmptySpellTexture"] or cfg.emptySpell:CreateTexture("HEDD_EmptySpellTexture","BACKGROUND")
	cfg.emptySpell.texture:SetAllPoints(cfg.emptySpell)
	cfg.emptySpell.texture:SetTexture(cfg.emptySpellIcon)
	cfg.emptySpell:Hide()
end
	
lib.ShowEmptySpellFrame = function()
	cfg.emptySpell:Show()
end

lib.SetSpellIcon = function(spell)
	cfg.spells[spell].f:SetWidth(cfg.isize)
	cfg.spells[spell].f:SetHeight(cfg.isize)
	cfg.spells[spell].f.texture = _G["HEDD_"..spell.."_text"] or cfg.spells[spell].f:CreateTexture("HEDD_"..spell.."_text","BACKGROUND")
	cfg.spells[spell].f.texture:SetAllPoints(cfg.spells[spell].f)
	cfg.spells[spell].f.texture:SetTexture(cfg.spells[spell].icon)
	cfg.spells[spell].f:Hide()
end

local index,id, sname
lib.AddSpell = function(spell,ids,noupdate,proc)
	for index,id in ipairs(ids) do
		sname = GetSpellInfo(id)
		if sname and (GetSpellInfo(sname) or proc) then
			cfg.spells[spell]={}
			if proc then
				cfg.spells[spell].proc=true 
			else
				cfg.spells[spell].proc=nil
			end
			cfg.spells[spell].id=id
			cfg.spells[spell].f = _G["HEDD_"..spell] or CreateFrame("Frame","HEDD_"..spell,Heddframe)
			cfg.spells[spell].f:SetAllPoints(Heddframe)
			
			cfg.spells[spell].name, _, cfg.spells[spell].icon, cfg.spells[spell].powerCost, cfg.spells[spell].isFunnel, cfg.spells[spell].powerType, cfg.spells[spell].castingTime, cfg.spells[spell].minRange, cfg.spells[spell].maxRange = GetSpellInfo(id)
			
			lib.SetSpellIcon(spell)
			
			if not noupdate then
				lib.UpdateSpellCD(spell)
			end
			cfg.sp_conv[cfg.spells[spell].name]=spell
			
			cfg.spells[spell].noupdate=noupdate or nil
			cfg.spells[spell].cd = 0
			cfg.spells[spell].start = cfg.now
			cfg.spells[spell].isUsable = 1
			cfg.spells[spell].notEnoughMana = nil
			cfg.spells[spell].powerCost = 0
			cfg.spells[spell].castingTime = 0
			cfg.spells[spell].channel = 0
			return true
		end
	end
	return false
end

lib.KnownSpell = function(spell)
	if cfg.spells[spell] then return true end
	return nil
end

lib.AddRuneSpell = function(spell,ids,runemask)
	if lib.AddSpell(spell,ids,true) then
		cfg.spells[spell].rune=true
		cfg.spells[spell].noupdate=nil
		cfg.spells[spell].red = runemask[1]
		cfg.spells[spell].green = runemask[2]
		cfg.spells[spell].blue = runemask[3]
		cfg.spells[spell].numrunes = cfg.spells[spell].red + cfg.spells[spell].green + cfg.spells[spell].blue
		lib.UpdateSpellCD(spell)
		return true
	end
	return false
end

local pcd,pstart,pisUsable,pnotEnoughMana,ppowerCost,pcastingTime
local sstart, sduration, senabled
lib.UpdateSpellCD = function(spell)
	if cfg.spells[spell] then

		pcd,pstart,pisUsable,pnotEnoughMana,ppowerCost,pcastingTime = cfg.spells[spell].cd,cfg.spells[spell].start,cfg.spells[spell].isUsable,cfg.spells[spell].notEnoughMana,cfg.spells[spell].powerCost,cfg.spells[spell].castingTime
		sstart, sduration, senabled = GetSpellCooldown(cfg.spells[spell].id)

		if (sstart>0 and sduration>0) then -- and senabled
			cfg.spells[spell].cd=sduration
			cfg.spells[spell].start=sstart
		else
			cfg.spells[spell].cd=0
			cfg.spells[spell].start=cfg.now
		end
		cfg.spells[spell].isUsable,cfg.spells[spell].notEnoughMana = IsUsableSpell(cfg.spells[spell].id)
		_, _, _, cfg.spells[spell].powerCost, _, _, cfg.spells[spell].castingTime = GetSpellInfo(cfg.spells[spell].id)
		
		if cfg.spells[spell].cd ~= pcd or cfg.spells[spell].start ~= pstart or cfg.spells[spell].isUsable~=pisUsable or cfg.spells[spell].notEnoughMana~=pnotEnoughMana or cfg.spells[spell].powerCost~=ppowerCost or cfg.spells[spell].castingTime~=pcastingTime then
			return true
		end
	end
	return nil
end

local phaveTotem, ptotemName, pstartTime, pduration, ppowerCost, pcastingTime
lib.UpdateTotem = function(totemtype)
	totemtype = totemtype or 1
	if not cfg.totems then cfg.totems={} end
	if not cfg.totems[totemtype] then
		cfg.totems[totemtype]={}
		cfg.totems[totemtype].haveTotem, cfg.totems[totemtype].totemName, cfg.totems[totemtype].startTime, cfg.totems[totemtype].duration, cfg.totems[totemtype].icon = GetTotemInfo(totemtype)
		return true
	end
	phaveTotem, ptotemName, pstartTime, pduration=cfg.totems[totemtype].haveTotem,cfg.totems[totemtype].totemName,cfg.totems[totemtype].startTime,cfg.totems[totemtype].duration
	cfg.totems[totemtype].haveTotem,cfg.totems[totemtype].totemName,cfg.totems[totemtype].startTime,cfg.totems[totemtype].duration = GetTotemInfo(totemtype)
	
	if phaveTotem~=cfg.totems[totemtype].haveTotem or ptotemName~=cfg.totems[totemtype].totemName or pstartTime~=cfg.totems[totemtype].startTime or pduration~=cfg.totems[totemtype].duration then
		return true
	end
	return nil
end

local tl_totem
lib.GetTotem = function(totemtype)
	if not cfg.totems then lib.UpdateTotem(totemtype) end
	if not cfg.totems[totemtype].haveTotem then return 0 end
	
	tl_totem = cfg.totems[totemtype].duration - (cfg.now-cfg.totems[totemtype].startTime)
	tl_totem = (tl_totem>0) and tl_totem or 0
	
	return tl_totem
end

lib.HaveTotem = function(spell,totemtype)
	totemtype=totemtype or 1
	if cfg.spells[spell] and cfg.totems[totemtype] and lib.GetTotem(totemtype)>0 and cfg.spells[spell].name==cfg.totems[totemtype].totemName then return true end
	return nil
end

lib.updateRune = function(rune)
	if not rune then return nil end
	runeType = GetRuneType(rune)
	if runeType then
		if not cfg.runes then
			cfg.runes={}
		end
		if not cfg.runes[rune] then
			cfg.runes[rune]={}
			cfg.runes[rune].runeType=runeType
			cfg.runes[rune].start, cfg.runes[rune].duration, cfg.runes[rune].runeReady = GetRuneCooldown(rune)
			return true
		else
			pstart,pduration,pruneReady,pruneType = cfg.runes[rune].start, cfg.runes[rune].duration, cfg.runes[rune].runeReady,runeType
			cfg.runes[rune].runeType=runeType
			cfg.runes[rune].start, cfg.runes[rune].duration, cfg.runes[rune].runeReady = GetRuneCooldown(rune)
			if pstart~=cfg.runes[rune].start or pduration~=cfg.runes[rune].duration or pruneReady~=cfg.runes[rune].runeReady or pruneType~=cfg.runes[rune].runeType then
				return true
			end
		end
	end
	return nil
end

local allrunesupdate
lib.updateAllRunes = function()
	allrunesupdate=nil
	for i_runes = 1, 6 do
		if lib.updateRune(i_runes) then allrunesupdate=true end
	end
	return allrunesupdate
end

lib.RuneReadyNum = function(runeType,useDeath)
	count = 0
	for i = 1,6 do
		if (cfg.runes[i].runeType == runeType or (cfg.runes[i].runeType == 4 and useDeath)) and lib.GetRuneCD(i) == 0 then
			count = count + 1
		end
	end
	return count
end


lib.RuneTypeCD = function(runeType,useGCD)
	c_rune = 0
	tl_rune=99999
	numrunes=0

	if runeType==1 then
		start,finish=1,2
	elseif runeType==2 then
		start,finish=3,4
	else
		start,finish=5,6
	end
	
	local wait = 0
	if useGCD and cfg.gcd then
		wait=cfg.spells[cfg.gcd].cd
	end
	
	for i_runes = start, finish do
		tl_rune_any =  cfg.runes[i_runes].duration - (cfg.now + wait - cfg.runes[i_runes].start)
		tl_rune_any = (tl_rune_any>=0) and tl_rune_any or 0
		if tl_rune_any==0 then
			numrunes=numrunes+1
		else
			if tl_rune_any<tl_rune then
				tl_rune=tl_rune_any
			end
		end
	end
	return numrunes, tl_rune
end

lib.GetRuneCD = function(rune)
	if not cfg.runes or not cfg.runes[rune] then return 0 end
	tl_rune =  cfg.runes[rune].duration - (cfg.now - cfg.runes[rune].start)
	tl_rune = (tl_rune>=0) and tl_rune or 0

	return tl_rune
end

lib.FullDeplatedRunes = function()
	allrunes=0
	for i_runes = 1,3 do
		numrunes=0
		c_rune = 0
		tl_rune=99999
		start,finish=i_runes*2-1,i_runes*2
		
		for i_runes = start, finish do
			tl_rune_any =  cfg.runes[i_runes].duration - (cfg.now - cfg.runes[i_runes].start)
			tl_rune_any = (tl_rune_any>=0) and tl_rune_any or 0
			if tl_rune_any==0 then
				numrunes=numrunes+1
			end
		end
		allrunes = (numrunes==0) and (allrunes+1) or 0
	end
	return allrunes
end

lib.getruneCD = function(runeType,useDeath)
	c_rune = 0
	tl_rune=99999
	ReadyRuneFound=nil
	
	if runeType==1 then
		start,finish=1,2
	elseif runeType==2 then
		start,finish=3,4
	else
		start,finish=5,6
	end
	
	for i_runes = start, finish do
		if ReadyRuneFound then return 0 end
		if not ExcludeRunes[i_runes] and cfg.runes[i_runes].runeType==runeType then
			tl_rune_any =  cfg.runes[i_runes].duration - (cfg.now - cfg.runes[i_runes].start)
			tl_rune_any = (tl_rune_any>=0) and tl_rune_any or 0
			if tl_rune_any==0 then
				ReadyRuneFound=true
				ExcludeRunes[i_runes]=true
			else
				if tl_rune_any<tl_rune then
					tl_rune=tl_rune_any
					c_rune=i_runes
				end
			end
		end
	end
	if ReadyRuneFound then return 0 end
	
	if useDeath then
		for i_runes = 1, 6 do
			if ReadyRuneFound then return 0 end
			if not ExcludeRunes[i_runes] and cfg.runes[i_runes].runeType==4 then
				tl_rune_any =  cfg.runes[i_runes].duration - (cfg.now - cfg.runes[i_runes].start)
				tl_rune_any = (tl_rune_any>=0) and tl_rune_any or 0
				if tl_rune_any==0 then
					ReadyRuneFound=true
					ExcludeRunes[i_runes]=true
				else
					if tl_rune_any<tl_rune then
						tl_rune=tl_rune_any
						c_rune=i_runes
					end
				end
			end
		end	
	end
	if ReadyRuneFound then return 0 end
	ExcludeRunes[c_rune]=true
	
	return tl_rune
end

lib.AddAura = function(spell,id,atype,unit,caster)
	if not GetSpellInfo(id) then return end
	if atype=="buff" then
		unit=unit or "player"
	else
		atype="debuff"
		unit=unit or "target"
	end
	
	cfg.watchunits[unit]=true
	cfg.auras[spell] ={}
	cfg.auras[spell].id=id
	cfg.auras[spell].name = GetSpellInfo(id)
	cfg.auras[spell].duration=0
	cfg.auras[spell].expire=0
	cfg.auras[spell].stacks=0
	cfg.auras[spell].type=atype
	cfg.auras[spell].unit=unit
	cfg.auras[spell].caster=caster or "player"
	cfg.auras[spell].present=0
	lib.UpdateAura(spell)
end

lib.AddAuras = function(spell,ids,atype,unit)
	if atype=="buff" then
		unit=unit or "player"
	else
		atype="debuff"
		unit=unit or "target"
	end

	for index,id in ipairs(ids) do
		lib.AddAura(spell..index,id,atype,unit,"any")
	end
end

local pduration,pexpire,pstacks,ppresent
local aname, arank, aicon, acount, adebuffType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellId

local SearchUnitDebuff = function(unit,name,id,casterIsPlayer)
	aname, arank, aicon, acount, adispelType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellID, acanApplyAura, aisBossDebuff = UnitDebuff(unit,name)
	if (casterIsPlayer and (aunitCaster ~= 'player' and aunitCaster ~= 'pet')) or (id ~= nil and aspellID ~= id) then
		for i = 1,40 do
			aname, arank, aicon, acount, adispelType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellID, acanApplyAura, aisBossDebuff = UnitDebuff(unit,i)
			if aname == name and (id ~= nil and aspellID == id) and (casterIsPlayer and (aunitCaster == 'player' or aunitCaster == 'pet')) then
				return aname, arank, aicon, acount, adispelType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellID, acanApplyAura, aisBossDebuff
			end
		end
	elseif aname == name then				
		return aname, arank, aicon, acount, adispelType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellID, acanApplyAura, aisBossDebuff
	end
	return nil
end

local SearchUnitBuff = function(unit,name,id,casterIsPlayer)
	aname, arank, aicon, acount, adispelType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellID, acanApplyAura, aisBossDebuff = UnitBuff(unit,name)
	if (casterIsPlayer and (aunitCaster ~= 'player' and aunitCaster ~= 'pet')) or (id ~= nil and aspellID ~= id) then
		for i = 1,40 do
			aname, arank, aicon, acount, adispelType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellID, acanApplyAura, aisBossDebuff = UnitBuff(unit,i)
			if aname == name and (id ~= nil and aspellID == id) and (casterIsPlayer and (aunitCaster == 'player' or aunitCaster == 'pet')) then
				return aname, arank, aicon, acount, adispelType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellID, acanApplyAura, aisBossDebuff
			end
		end
	elseif aname == name then				
		return aname, arank, aicon, acount, adispelType, aduration, aexpirationTime, aunitCaster, aisStealable, ashouldConsolidate, aspellID, acanApplyAura, aisBossDebuff
	end
	return nil
end
	
			
lib.UpdateAura = function(spell)
	if cfg.auras[spell] then
		pduration,pexpire,pstacks,ppresent=cfg.auras[spell].duration,cfg.auras[spell].expire,cfg.auras[spell].stacks,cfg.auras[spell].present
		if cfg.auras[spell].type=="debuff" then
			aname, _, _, acount, _, aduration, aexpirationTime, aunitCaster, _, _, _ = SearchUnitDebuff(cfg.auras[spell].unit, cfg.auras[spell].name, cfg.auras[spell].id, true)
			--UnitDebuff(cfg.auras[spell].unit, cfg.auras[spell].name)
			if cfg.auras[spell].name==aname and ((cfg.auras[spell].caster=="player" and hedlib.isPlayer(aunitCaster)) or cfg.auras[spell].caster=="any") then
				cfg.auras[spell].duration=aduration
				cfg.auras[spell].expire=aexpirationTime
				cfg.auras[spell].stacks=acount or 1
				cfg.auras[spell].present=1
			else
				cfg.auras[spell].duration=0
				cfg.auras[spell].expire=0
				cfg.auras[spell].stacks=0
				cfg.auras[spell].present=0
			end
		else
			aname, _, _, acount, _, aduration, aexpirationTime, aunitCaster, _, _, _ = SearchUnitBuff(cfg.auras[spell].unit, cfg.auras[spell].name, cfg.auras[spell].id)
			if cfg.auras[spell].name==aname and ((cfg.auras[spell].caster=="player" and hedlib.isPlayer(aunitCaster)) or cfg.auras[spell].caster=="any") then
				cfg.auras[spell].duration=aduration
				cfg.auras[spell].expire=aexpirationTime
				cfg.auras[spell].stacks=acount or 1
				cfg.auras[spell].present=1
			else
				cfg.auras[spell].duration=0
				cfg.auras[spell].expire=0
				cfg.auras[spell].stacks=0
				cfg.auras[spell].present=0
			end
		end
		
		if pduration~=cfg.auras[spell].duration or pexpire~=cfg.auras[spell].expire or pstacks~=cfg.auras[spell].stacks or ppresent~=cfg.auras[spell].ppresent then
			return true
		end
	end
	return nil
end

local tl_aura, n_aura
lib.GetAura = function(auras)
	tl_aura = 0
	for _,n_aura in ipairs(auras) do
		if cfg.auras[n_aura] then
			tl_aura=cfg.auras[n_aura].expire-cfg.now
			tl_aura = (tl_aura>=0) and tl_aura or 0
			if cfg.auras[n_aura].present==1 and tl_aura==0 then tl_aura=99999 end
			if tl_aura>0 then 
				return tl_aura
			end
		end
	end
	return 0
end

local tl_caura
lib.GetShortestAura = function(auras)
	tl_aura=99999
	for _,n_aura in ipairs(auras) do
		if cfg.auras[n_aura] then
			tl_caura=cfg.auras[n_aura].expire-cfg.now
			tl_caura = (tl_caura>=0) and tl_caura or 0
			if tl_caura<tl_aura then tl_aura=tl_caura end
		end
	end
	if tl_aura==99999 then return 0 end
	return tl_aura
end

lib.GetLargestAura = function(auras)
	tl_aura=0
	for _,n_aura in ipairs(auras) do
		if cfg.auras[n_aura] then
			tl_caura=cfg.auras[n_aura].expire-cfg.now
			tl_caura = (tl_caura>=0) and tl_caura or 0
			if tl_caura>tl_aura then tl_aura=tl_caura end
		end
	end
	return tl_aura
end

local bignumber,n_num
lib.GetLargestNumber = function(numbers)
	bignumber=0
	for _,n_num in ipairs(numbers) do
		if n_num>bignumber then bignumber=n_num end
	end
	return bignumber
end

lib.GetAuraNum = function(aura)
	tl_aura=0
	if cfg.auras[aura] then
		tl_aura=cfg.auras[aura].expire-cfg.now
		tl_aura = (tl_aura>=0) and tl_aura or 0
		if cfg.auras[aura].present==1 and tl_aura==0 then tl_aura=99999 end
		if tl_aura>0 then return (cfg.auras[aura].stacks) end
	end
	return 0
end

local i_aura,notfound_aura
lib.GetAuras = function(aura)
	tl_aura = 0
	i_aura=1
	notfound_aura=true
	while notfound_aura do
		n_aura=aura..i_aura
		if cfg.auras[n_aura] then
			tl_aura = cfg.auras[n_aura].expire-cfg.now
			tl_aura = (tl_aura>=0) and tl_aura or 0
			if tl_aura>0 then 
				notfound_aura=nil
				return tl_aura
			end
			i_aura=i_aura+1
		else
			notfound_aura=nil
		end
	end
	return 0
end

lib.UpdateWeaponBuffs = function()
	pMain, pOff = cfg.Weapons.Main, cfg.Weapons.Off
	cfg.Weapons.Main, _, _, cfg.Weapons.Off = GetWeaponEnchantInfo()
	if pMain~=cfg.Weapons.Main or pOff~=cfg.Weapons.Off then return true end
	return false
end

lib.SimpleCDCheck = function (spell, Wait,nousecheck) -- nomanacheck, nousecheck, useGCD
	local compensate = 0
	--print(cfg.compensatePower)
	if cfg.compensatePower and cfg.compensatePower > 0 then
		compensate = cfg.compensatePower
	end
	--[[if spell == "MS" then
		print(compensate..','..cfg.compensatePower.."+"..cfg.power..">="..cfg.spells[spell].powerCost)
	end]]
	if cfg.spells[spell] and ((cfg.spells[spell].notEnoughMana and cfg.spells[spell].powerCost <= cfg.power + compensate and cfg.spells[spell].powerType == UnitPowerType('player')) or (not cfg.spells[spell].notEnoughMana and cfg.spells[spell].isUsable==1) or nousecheck)  then
--[[		if useGCD and cfg.gcd and cfg.spells[cfg.gcd] then
			tl_spell=cfg.spells[cfg.gcd].cd - (cfg.now - cfg.spells[cfg.gcd].start)
		else]]
			tl_spell=cfg.spells[spell].cd - (cfg.now - cfg.spells[spell].start)
--s		end
		tl_spell = (tl_spell>=0) and tl_spell or 0
		
		Wait=Wait or 0
		if Wait>tl_spell then tl_spell=Wait end
		
		if cfg.casting and cfg.castEnd>cfg.now and ((cfg.showchannel and cfg.ischanneling) or (not cfg.ischanneling)) then
			ctl=(cfg.castEnd-cfg.now)
			if ctl>tl_spell then tl_spell=ctl end
		end
		
--[[		if cfg.power<cfg.spells[spell].powerCost and cfg.pactiveRegen>0 then
			tl_spell_energy=(cfg.spells[spell].powerCost-cfg.power)/cfg.pactiveRegen
			if tl_spell_energy>tl_spell then tl_spell=tl_spell_energy end
		end]]
		
		if tl_spell==0 or tl_spell<=(cfg.mintime+cfg.react) then
			lib.UpdateBar(spell,tl_spell)
			cfg.cmintime=tl_spell
			return true
		else
			if cfg.cmintime>tl_spell then
				cfg.cmintime=tl_spell
			end
		end
	end
	return nil
end

lib.EnergyCDCheck = function (spell,Wait,priospell) --useGCD
	if cfg.spells[spell] then
		if useGCD and cfg.gcd and cfg.spells[cfg.gcd] then
			tl_spell=cfg.spells[cfg.gcd].cd - (cfg.now - cfg.spells[cfg.gcd].start)
		else
			tl_spell=cfg.spells[spell].cd - (cfg.now - cfg.spells[spell].start)
		end
		tl_spell = (tl_spell>=0) and tl_spell or 0
		
		Wait=Wait or 0
		if Wait>tl_spell then tl_spell=Wait end
		
		cpower=0
		if cfg.casting and cfg.sp_conv[cfg.casting] and cfg.castEnd>cfg.now and ((cfg.showchannel and cfg.ischanneling) or (not cfg.ischanneling)) then
			ctl=(cfg.castEnd-cfg.now)
			if ctl>tl_spell then tl_spell=ctl end
			cpower=cfg.spells[cfg.sp_conv[cfg.casting]].powerCost
		end
	
		cpower=cfg.power+cfg.pactiveRegen*tl_spell-cpower
		if cpower<cfg.spells[spell].powerCost then
			if priospell and cfg.spells[priospell] then return nil end
			tl_spell=(cfg.spells[spell].powerCost-cfg.power)/cfg.pactiveRegen
		end
		
		if priospell and cfg.spells[priospell] then
			tl_cspell=cfg.spells[priospell].cd - (cfg.now - cfg.spells[priospell].start)
			tl_cspell = (tl_cspell>=0) and tl_cspell or 0
			
			ct_spell=cfg.spells[spell].castingTime/1000
			
			if (ct_spell>0 and ct_spell<1) or ct_spell==0 then ct_spell=1 end
			ct_spell=tl_spell+ct_spell
			
			if tl_cspell>ct_spell then
				cpower=cfg.power+cfg.pactiveRegen*tl_cspell
			else
				cpower=cfg.power+cfg.pactiveRegen*ct_spell
			end
			
			cpower=cpower-cfg.spells[spell].powerCost-cfg.spells[priospell].powerCost
			if cpower<0 then return nil end
		end
		
		if tl_spell==0 or tl_spell<=(cfg.mintime+cfg.react) then
			lib.UpdateBar(spell,tl_spell)
			cfg.cmintime=tl_spell
			return true
		else
			if cfg.cmintime>tl_spell then
				cfg.cmintime=tl_spell
			end
		end
	end
	return nil
end

lib.RuneCDCheck = function (spell,useDeath,twospells,useGCD,minWait)
	minWait=minWait or 0
	ExcludeRunes = {}

	if cfg.spells[spell] then
		if useGCD and cfg.gcd then
			tl_spell=cfg.spells[cfg.gcd].cd - (cfg.now - cfg.spells[cfg.gcd].start)
		else
			tl_spell=cfg.spells[spell].cd - (cfg.now - cfg.spells[spell].start)
		end
		tl_spell = (tl_spell>=0) and tl_spell or 0
		
		tl_rune_r,tl_rune_g,tl_rune_b = 0,0,0
		n_rune_r,n_rune_g,n_rune_b = 0,0,0
		
		for j = 1,2 do
			if cfg.spells[spell].red==1 then
				tl_rune_r=lib.getruneCD(1,useDeath)
				if ReadyRuneFound then n_rune_r = n_rune_r+1 end
			else
				n_rune_r=2
			end
		
			if cfg.spells[spell].green==1 then
				tl_rune_g=lib.getruneCD(2,useDeath)
				if ReadyRuneFound then n_rune_g = n_rune_g+1 end
			else
				n_rune_g=2
			end
		
			if cfg.spells[spell].blue==1 then
				tl_rune_b=lib.getruneCD(3,useDeath)
				if ReadyRuneFound then n_rune_b = n_rune_b+1 end
			else
				n_rune_b=2
			end
			
			if not twospells then break end
		end
		
		if twospells and n_rune_r==2 and n_rune_g==2 and n_rune_b==2 then
			lib.UpdateBar(spell,0)
			return true
		end
		
		if n_rune_r>0 and n_rune_g>0 and n_rune_b>0 then
			tl_spell=tl_spell
		else
			if tl_spell<tl_rune_r then tl_spell=tl_rune_r end
			if tl_spell<tl_rune_g then tl_spell=tl_rune_g end
			if tl_spell<tl_rune_b then tl_spell=tl_rune_b end
		end
		
		if tl_spell==0 or tl_spell<=minWait or tl_spell==cfg.mintime then
			lib.UpdateBar(spell,tl_spell)
			cfg.cmintime=tl_spell
			return true
		else
			if cfg.cmintime>tl_spell then
				cfg.cmintime=tl_spell
			end
		end
	end
	return nil
end

lib.GetRuneSpellCD=function(spell,useDeath,useGCD)
	ExcludeRunes = {}
	if cfg.spells[spell] then
		if useGCD then
			tl_spell=cfg.spells[cfg.gcd].cd - (cfg.now - cfg.spells[cfg.gcd].start)
		else
			tl_spell=cfg.spells[spell].cd - (cfg.now - cfg.spells[spell].start)
		end
		tl_spell = (tl_spell>=0) and tl_spell or 0
		
		tl_rune_r,tl_rune_g,tl_rune_b = 0,0,0
		n_rune_r,n_rune_g,n_rune_b = 0,0,0

		if cfg.spells[spell].red==1 then
			tl_rune_r=lib.getruneCD(1,useDeath)
			if ReadyRuneFound then n_rune_r = n_rune_r+1 end
		else
			n_rune_r=1
		end
		
		if cfg.spells[spell].green==1 then
			tl_rune_g=lib.getruneCD(2,useDeath)
			if ReadyRuneFound then n_rune_g = n_rune_g+1 end
		else
			n_rune_g=1
		end
		
		if cfg.spells[spell].blue==1 then
			tl_rune_b=lib.getruneCD(3,useDeath)
			if ReadyRuneFound then n_rune_b = n_rune_b+1 end
		else
			n_rune_b=1
		end
			
		if n_rune_r>0 and n_rune_g>0 and n_rune_b>0 then
			tl_spell=tl_spell
		else
			if tl_spell<tl_rune_r then tl_spell=tl_rune_r end
			if tl_spell<tl_rune_g then tl_spell=tl_rune_g end
			if tl_spell<tl_rune_b then tl_spell=tl_rune_b end
		end

		return tl_spell
	end
	return 0
end

local tl_spell_cd
lib.GetSpellCD = function (spell,nopower)
	tl_spell_cd=0
	if cfg.spells[spell] then
		tl_spell_cd=cfg.spells[spell].cd - (cfg.now - cfg.spells[spell].start)
		tl_spell_cd = (tl_spell_cd>=0) and tl_spell_cd or 0
		if not nopower and cfg.power<cfg.spells[spell].powerCost and cfg.pactiveRegen>0 then
			tl_spell_energy=(cfg.spells[spell].powerCost-cfg.power)/cfg.pactiveRegen
			if tl_spell_energy>tl_spell_cd then tl_spell_cd=tl_spell_energy end
		end
	end
	return tl_spell_cd
end

lib.GetSpellCost = function (spell)
	if cfg.spells[spell] then
		return cfg.spells[spell].powerCost
	end
	return 0
end

lib.GetSpellName = function (spell)
	if cfg.spells[spell] then
		return cfg.spells[spell].name
	end
	return "nospell"
end

local sname,stime
lib.GetLastSpell = function (spells)
	for _,cspell in ipairs(spells) do
		if cfg.spells[cspell] and cfg.spellcast[cfg.spells[cspell].name] then
--[[			if cfg.lastspell==cfg.spells[cspell].name and cfg.now<(cfg.spellcast[cfg.lastspell]-cfg.spells[cspell].castingTime+1)then
				return true
			end]]
			if cfg.now<(cfg.spellcast[cfg.spells[cspell].name]-cfg.spells[cspell].castingTime+1) then
				return true
			end
		end
	end
	return nil
end

lib.GetLast2Spell = function (spells)
	for index,spell in ipairs(spells) do
		if cfg.spells[spell] and cfg.lastspell2==cfg.spells[spell].name then
			return true
		end
	end
	return nil
end

lib.GetSpellCT = function (spell)
	if cfg.spells[spell] then
		return cfg.spells[spell].castingTime/1000
	end
	return 0
end

lib.GetCastingSpell=function()
	if cfg.casting and cfg.castEnd>cfg.now then
		return cfg.sp_conv[cfg.casting]
	end
	return nil
end

lib.SpellCasting=function(spell)
	if cfg.spells[spell] then
		if cfg.casting==cfg.spells[spell].name and cfg.castEnd>cfg.now then
			return true, spell
		else
			return nil, cfg.sp_conv[cfg.casting]
		end
	else
		if cfg.casting and cfg.castEnd>cfg.now then
			return true, cfg.sp_conv[cfg.casting]
		else
			return nil
		end
	end
end

local t2w,tl_spell_cast
lib.Time2Wait=function(spell)
	t2w=0
	if not spell then spell=cfg.gcd end
	if spell and cfg.spells[spell] then 
		t2w=cfg.spells[spell].cd - (cfg.now - cfg.spells[spell].start)
		t2w = (t2w>=0) and t2w or 0
		if cfg.power<cfg.spells[spell].powerCost and cfg.pactiveRegen>0 then
			tl_spell_energy=(cfg.spells[spell].powerCost-cfg.power)/cfg.pactiveRegen
			if tl_spell_energy>t2w then t2w=tl_spell_energy end
		end
		if cfg.casting and cfg.castEnd>cfg.now then
			tl_spell_cast=cfg.castEnd-cfg.now
			if tl_spell_cast>t2w then t2w=tl_spell_cast end
		end
	end
	return t2w
end

lib.SpellCastingLeft=function(spell)
	if cfg.spells[spell] then
		if cfg.casting==cfg.spells[spell].name and cfg.castEnd>cfg.now then
			return (cfg.castEnd-cfg.now)
		else
			return 0
		end
	else
		if cfg.casting and cfg.castEnd>cfg.now then
			return (cfg.castEnd-cfg.now)
		else
			return 0
		end
	end
end

lib.MaxEnergy = function()
	return (cfg.powermax-cfg.power)/cfg.pactiveRegen
end

lib.TimeEnergy = function(t)
	return (cfg.power+cfg.pactiveRegen*t)
end

lib.TimeEnergyGain = function(t)
	return (cfg.pactiveRegen*t)
end

local pcombo
lib.ComboUpdate = function()
	pcombo = cfg.combo
	cfg.combo = GetComboPoints('player', 'target')
	if pcombo~=cfg.combo then
		return true
	end
	return nil
end

local ppower
lib.HolyPowerUpdate = function()
	ppower = cfg.holy
	cfg.holy = UnitPower("player" , SPELL_POWER_HOLY_POWER)
	if ppower~=cfg.holy then
		return true
	end
	return nil
end

cfg.chi=0
lib.ChiPowerUpdate = function()
	ppower = cfg.chi
	cfg.chi = UnitPower("player" , SPELL_POWER_CHI)
	if ppower~=cfg.chi then
		return true
	end
	return nil
end

cfg.orbs=0
lib.OrbsUpdate = function()
	ppower = cfg.orbs
	cfg.orbs = UnitPower("player" , 13)
	if ppower~=cfg.orbs then
		return true
	end
	return nil
end

cfg.warlockres=0
lib.WarlockResourceUpdate = function(resType)
	ppower = cfg.warlockres
	cfg.warlockres = UnitPower("player" , resType , true)
	if ppower~=cfg.warlockres then
		return true
	end
	return nil
end
local pground
lib.GroundUpdate = function()
	pground=cfg.onGround
	if IsFalling() or IsFlying() then
		cfg.onGround=nil
	else
		cfg.onGround=true
	end
	
	if pground~=cfg.onGround then
		return true
	end
	return nil
end

local shape
lib.shape = function()
	shape=GetShapeshiftFormID()
	if shape and cfg.shapes[shape] then return cfg.shapes[shape] end
	return "human"
end



local itemSET
lib.UpdateSet = function()
	cfg.setitems={}
	for itemSET, _ in pairs(cfg.set) do
		cfg.setitems[itemSET]=0
		for _, itemID in pairs(cfg.set[itemSET]) do
			for i=0,19 do
				if cfg.equip[i] and cfg.equip[i]==itemID then
					cfg.setitems[itemSET]=cfg.setitems[itemSET]+1
				end
			end
		end
	end
end

lib.SetBonus=function(set)
	if cfg.setitems[set] then
		if cfg.setitems[set]>=4 then
			return 2
		elseif cfg.setitems[set]>=2 then
			return 1
		end
	end
	return 0
end

lib.UpdateEquip=function(slot)
	cfg.equip[slot]=GetInventoryItemID("player", slot)
end

lib.UpdateEquipAll=function()
	for i=0,19 do
		lib.UpdateEquip(i)
	end
	lib.UpdateSet()
end

lib.onspellupdate = function()
	if cfg.mode~="dps" then
		for _,cspell in ipairs(cfg.spells_single) do
			if cfg.spells[cspell] and (cfg.lastspell==cfg.spells[cspell].name or (cfg.casting and cfg.casting==cfg.spells[cspell].name)) then
				cfg.mode = "dps"
				cfg.plist=cfg.plistdps
				cfg.Update=true
				return
			end
		end
	end
	
	if cfg.mode~="aoe" then
		for _,cspell in ipairs(cfg.spells_aoe) do
			if cfg.spells[cspell] and (cfg.lastspell==cfg.spells[cspell].name or (cfg.casting and cfg.casting==cfg.spells[cspell].name)) then
				cfg.mode = "aoe"
				cfg.plist=cfg.plistaoe
				cfg.Update=true
				return
			end
		end
	end
	
	if cfg.mode~="range" then
		for _,cspell in ipairs(cfg.spells_range) do
			if cfg.spells[cspell] and (cfg.lastspell==cfg.spells[cspell].name or (cfg.casting and cfg.casting==cfg.spells[cspell].name)) then
				cfg.mode = "range"
				cfg.plist=cfg.plistrange
				cfg.Update=true
				return
			end
		end
	end
end

lib.Power = function()
	if cfg.power>=0 and cfg.powermax>0 then
		return (cfg.power*100/cfg.powermax)
	end
	return 0
end

lib.SaveSpell = function(spellname)
	cfg.spellcast[spellname]=cfg.now
	cfg.lastspell2=cfg.lastspell
	cfg.lastspell=spellname
	cfg.lastspell_time=cfg.now
end

lib.GetLastCast = function(spellname)
	if cfg.spellcast[spellname] then return (cfg.now-cfg.spellcast[spellname]) end
	return 99999
end

local smallest,timer
lib.GetSmallest = function(timers)
	smallest=99999
	for _,timer in ipairs(timers) do
		if smallest>timer then smallest=timer end
	end
	return smallest
end
ns.lib = lib
lib.InitEmptySpellFrame()